home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / apps.to.go / DTS.Lib / Print.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-20  |  10.7 KB  |  390 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:     DTS.Lib
  5. ** File:        print.c
  6. ** Written by:  Eric Soldan
  7. ** Based on:    Code from Pete "Luke" Alexander.
  8. **
  9. ** Copyright © 1989-1991 Apple Computer, Inc.
  10. ** All rights reserved.
  11. */
  12.  
  13. /* You may incorporate this sample code into your applications without
  14. ** restriction, though the sample code has been provided "AS IS" and the
  15. ** responsibility for its operation is 100% yours.  However, what you are
  16. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  17. ** after having made changes. If you're going to re-distribute the source,
  18. ** we require that you make it clear in the source that the code was
  19. ** descended from Apple Sample Code, but that you've made changes. */
  20.  
  21.  
  22.  
  23. /*****************************************************************************/
  24.  
  25.  
  26.  
  27. #include "DTS.Lib2.h"
  28. #include "DTS.Lib.protos.h"
  29.  
  30. #ifndef __ERRORS__
  31. #include <Errors.h>
  32. #endif
  33.  
  34. #ifndef __RESOURCES__
  35. #include <Resources.h>
  36. #endif
  37.  
  38. #ifndef __STRINGUTILS__
  39. #include "StringUtils.h"
  40. #endif
  41.  
  42.  
  43.  
  44. /*****************************************************************************/
  45.  
  46.  
  47.  
  48. static pascal void    PrintIdleProc(void);
  49. short                gPrintPage;
  50. static DialogPtr    gPrintingStatusDialog;
  51.  
  52.  
  53.  
  54. /*****************************************************************************/
  55.  
  56.  
  57.  
  58. /* This print-loop function is designed to be called under various situations.
  59. ** The big issue that it handles is finder printing.  If multiple documents
  60. ** are to be printed from the finder, the user should only see one job dialog
  61. ** for all the files.  (If a job dialog is shown for each file, how does the
  62. ** user know for which file the dialog is for?)  So, for situations where
  63. ** there is more than one file to be printed, call this code the first time
  64. ** with the firstJob boolean true.  Normally, the jobDlg boolean will also
  65. ** be true, except that under 7.0, you may be printing in the background.
  66. ** If this is the case, you don't want a job dialog for even the first file,
  67. ** and you should pass in false for the jobDlg boolean in this case.  For
  68. ** files 2-N, you should pass false for both booleans.  For regular application
  69. ** printing, you should pass true for both booleans, since the file is the
  70. ** first (only) file, and you are not in the background.
  71. **
  72. ** After calling this function to print a document, you need to call it
  73. ** again with a nil document handle.  The print record for the first (or only)
  74. ** document printed is preserved in a static variable.  This is so that the
  75. ** job dialog information can be passed on to documents 2-N in the print job.
  76. ** Calling this function with the document handle nil tells this function
  77. ** that you are done printing documents, and that the print record for the
  78. ** first job can be disposed of. */
  79.  
  80. #pragma segment Print
  81. OSErr    PrintDocument(FileRecHndl frHndl, Boolean jobDlg, Boolean firstJob)
  82. {
  83.     OSErr            err;
  84.     THPrint            prRecHndl;
  85.     TPPrPort        printPort;
  86.     GrafPtr            oldPort;
  87.     short            i, keepResFile, copies, fstPage, lstPage;
  88.     TPrStatus        status;
  89.     ControlHandle    proceedButton;
  90.     Rect             rct;
  91.     Handle            txtHndl;
  92.     Str255            txt, txt2;
  93.     PrIdleUPP        pidleupp;
  94.  
  95.     static THPrint    prMergeHndl;
  96.  
  97.     if (!frHndl) {
  98.         if (prMergeHndl) {
  99.             DisposeHandle((Handle)prMergeHndl);
  100.             prMergeHndl = nil;
  101.         }
  102.         return(noErr);
  103.     }
  104.  
  105.     gPrintingStatusDialog = nil;
  106.  
  107.     if (!(prRecHndl = (THPrint)NewHandle(sizeof(TPrint)))) return(memFullErr);
  108.         /* If we can't generate a print record handle, we are out of here. */
  109.  
  110.     BlockMove((Ptr)&((*frHndl)->d.doc.fhInfo.print), (Ptr)(*prRecHndl), sizeof(TPrint));
  111.         /* Get the document's print info into the print record handle. */
  112.  
  113.     GetPort(&oldPort);
  114.  
  115.     DoSetCursor(&qd.arrow);
  116.  
  117.     keepResFile = CurResFile();
  118.     PrOpen();
  119.     err = PrError();
  120.  
  121.     if (!err) {
  122.         if (!(*frHndl)->d.doc.fhInfo.printRecValid) {
  123.             PrintDefault(prRecHndl);            /* The document print record was never 
  124.             err = PrError();                    ** initialized.  Now is is. */
  125.         }
  126.         if (!err) {
  127.             PrValidate(prRecHndl);        /* Do this just 'cause Apple says so. */
  128.             err = PrError();
  129.         }
  130.         if (!err) {
  131.             if (jobDlg) {                /* User gets to click some buttons. */
  132.                 UnhiliteWindows();
  133.                 if (!(PrJobDialog(prRecHndl)))
  134.                     err = userCanceledErr;
  135.                 else
  136.                     err = PrError();
  137.                 HiliteWindows();
  138.             }
  139.         }
  140.         if (!err) {
  141.             if (!firstJob) {
  142.                 fstPage = (*prMergeHndl)->prJob.iFstPage;
  143.                 lstPage = (*prMergeHndl)->prJob.iLstPage;
  144.                 PrJobMerge(prMergeHndl, prRecHndl);
  145.                 (*prMergeHndl)->prJob.iFstPage = (*prRecHndl)->prJob.iFstPage = fstPage;
  146.                 (*prMergeHndl)->prJob.iLstPage = (*prRecHndl)->prJob.iLstPage = lstPage;
  147.                 err = PrError();
  148.                     /* For documents other than the first, do the PrJobMerge thing.
  149.                     ** Unfortunately, PrJobMerge is kind of broken.  The first and last
  150.                     ** page fields have to be cached and put back.  The rest of PrJobMerge
  151.                     ** seems to work okay. */
  152.             }
  153.         }
  154.  
  155.         if (!err) {            /* Put the defaulted/validated/jobDlg'ed print record in the doc. */
  156.             pidleupp = nil;
  157.             fstPage = (*prRecHndl)->prJob.iFstPage;
  158.             lstPage = (*prRecHndl)->prJob.iLstPage;
  159.             copies  = (*prRecHndl)->prJob.iCopies;
  160.             BlockMove((Ptr)(*prRecHndl), (Ptr)&((*frHndl)->d.doc.fhInfo.print), sizeof(TPrint));
  161.             (*frHndl)->d.doc.fhInfo.printRecValid = true;
  162.  
  163.             gPrintingStatusDialog = nil;
  164.             i = ((*prRecHndl)->prStl.wDev >> 8) & 0xFF;
  165.             if ((i == 1) || (i == 2))
  166.                 gPrintingStatusDialog = GetNewDialog(rPrStatusDlg, nil, (WindowPtr)-1);
  167.             if (gPrintingStatusDialog) {
  168.                     /* The ImageWriter driver uses ParamText, so we can’t.
  169.                     ** If we try to, then the printer name shows up, instead of
  170.                     ** the document name.  Due to this, we have to parse our
  171.                     ** own text.  We expect dialog item#4 to have a c/r in it.
  172.                     ** We use the c/r instead of ^0, due to the ImageWriter driver.
  173.                     ** We just replace the c/r with the name of the document. */
  174.                 GetDialogItem(gPrintingStatusDialog, 4, &i, (Handle *)&txtHndl, &rct);
  175.                 GetDialogItemText(txtHndl, txt);
  176.                 for (i = *txt; i; --i) {
  177.                     if (txt[i] == 13) {
  178.                         txt[i] = *txt - i;
  179.                         txt[0] = i - 1;
  180.                         break;
  181.                     }
  182.                 }        /* We now have two pascal strings -- one right after the other. */
  183.                 pcpy(txt2, txt);                                /* Copy the first string. */
  184.                 pcat(txt2, (*frHndl)->fileState.fss.name);        /* Append the document name. */
  185.                 pcat(txt2, txt + *txt + 1);                        /* Append the second string. */
  186.                 SetDialogItemText(txtHndl, txt2);
  187.                 GetDialogItem(gPrintingStatusDialog, 1, &i, (Handle *)&proceedButton, &rct);
  188.                 HiliteControl(proceedButton, 255);
  189.                     /* Setup the proceed/pause/cancel dialog with the document name. */
  190.                 pidleupp = NewPrIdleProc(PrintIdleProc);
  191.                 (*prRecHndl)->prJob.pIdleProc = pidleupp;
  192.                 UseResFile(keepResFile);        /* Hook in the proceed/pause/cancel dialog. */
  193.                 UnhiliteWindows();
  194.             }
  195.  
  196.             for (i = 1; (i <= copies) && (!err); ++i) {
  197.  
  198.                 printPort = PrOpenDoc(prRecHndl, nil, nil);
  199.                 if (!(err = PrError())) {
  200.  
  201.                     gPrintPage = 1;
  202.                     while (gPrintPage <= lstPage) {
  203.  
  204.                         PrOpenPage(printPort, nil);
  205.  
  206.                         if (!(err = PrError()))
  207.                             err = DoImageDocument(frHndl);
  208.                                 /* Do the print thing here. */
  209.  
  210.                         PrClosePage(printPort);
  211.  
  212.                         if (!gPrintPage) break;
  213.                         ++gPrintPage;
  214.                     }
  215.                     gPrintPage = 0;
  216.                 }
  217.                 PrCloseDoc(printPort);
  218.             }
  219.             if (pidleupp) {
  220.                 DisposeRoutineDescriptor(pidleupp);
  221.             }
  222.         }
  223.  
  224.         if (
  225.             (!err) &&
  226.             ((*prRecHndl)->prJob.bJDocLoop == bSpoolLoop) &&
  227.             (!(err = PrError()))
  228.         ) {
  229.             PrPicFile(prRecHndl, nil, nil, nil, &status);
  230.             err = PrError();
  231.         }
  232.     }
  233.  
  234.     if (firstJob)
  235.         prMergeHndl = prRecHndl;
  236.     else
  237.         DisposeHandle((Handle)prRecHndl);
  238.  
  239.     if (gPrintingStatusDialog)
  240.         DisposeDialog(gPrintingStatusDialog);
  241.  
  242.     PrClose();
  243.     UseResFile(keepResFile);
  244.  
  245.     SetPort(oldPort);
  246.     HiliteWindows();
  247.  
  248.     if (err == iIOAbortErr)
  249.         err = noErr;
  250.  
  251.     return(err);
  252. }
  253.  
  254.  
  255.  
  256. /*****************************************************************************/
  257.  
  258.  
  259.  
  260. /* DonePrinting makes sure that PrintDocument gets rid of the prMergeHndl
  261. ** print record that is used for multiple document printing.  Call this after
  262. ** or the last document is printed, or you get a memory leak. */
  263.  
  264. #pragma segment Print
  265. void    DonePrinting(void)
  266. {
  267.     PrintDocument(nil, false, false);
  268. }
  269.  
  270.  
  271.  
  272. /*****************************************************************************/
  273.  
  274.  
  275.  
  276. /* PrintIdleProc will handle events in the 'Printing Status Dialog' which
  277. ** gives the user the option to 'Proceed', 'Pause', or 'Cancel' the current
  278. ** printing job during print time.
  279. **
  280. ** The buttons:
  281. **        1: Proceed
  282. **        2: Pause
  283. **        3: Cancel
  284. */
  285.  
  286. #pragma segment Print
  287. pascal void    PrintIdleProc(void)
  288. {
  289.     Boolean                button, paused;
  290.     ControlHandle        pauseButton, proceedButton;
  291.     DialogPtr            aDialog;
  292.     EventRecord            anEvent;
  293.     GrafPtr                oldPort;
  294.     Rect                 rct;
  295.     short                item, itemType, keepResFile;
  296.  
  297.     GetPort(&oldPort);
  298.  
  299.     UseResFile(keepResFile = CurResFile());
  300.  
  301.     GetDialogItem(gPrintingStatusDialog, 1, &itemType, (Handle *)&proceedButton, &rct);
  302.     HiliteControl(proceedButton, 255);
  303.     GetDialogItem(gPrintingStatusDialog, 2, &itemType, (Handle *)&pauseButton, &rct);
  304.  
  305.     paused = false;
  306.     do {
  307.         if (GetNextEvent((mDownMask + mUpMask + updateMask), &anEvent)) {
  308.             if (gPrintingStatusDialog != FrontWindow())
  309.                 SelectWindow(gPrintingStatusDialog);
  310.  
  311.             if (IsDialogEvent(&anEvent)) {
  312.                 button = DialogSelect(&anEvent, &aDialog, &item);
  313.  
  314.                 if ((button) && (aDialog == gPrintingStatusDialog)) {
  315.                     switch (item) {
  316.                         case 1:
  317.                             HiliteControl(pauseButton, 0);        /* Enable PAUSE    */
  318.                             HiliteControl(proceedButton, 255);    /* Disable PROCEED */
  319.                             paused = false;
  320.                             break;
  321.                         case 2:
  322.                             HiliteControl(pauseButton, 255);    /* Disable PAUSE  */
  323.                             HiliteControl(proceedButton, 0);    /* Enable PROCEED */
  324.                             paused = true;
  325.                             break;
  326.                         case 3:
  327.                             PrSetError(iPrAbort);               /* CANCEL printing */
  328.                             paused = false;
  329.                             break;
  330.                     }
  331.                 }
  332.             }
  333.         }
  334.     } while (paused != false); 
  335.  
  336.     SetPort(oldPort);
  337. }
  338.  
  339.  
  340.  
  341. /*****************************************************************************/
  342.  
  343.  
  344.  
  345. /* Call this from the application to present a style dialog.  The changes are
  346. ** automatically saved in the document. */
  347.  
  348. #pragma segment Print
  349. OSErr    PresentStyleDialog(FileRecHndl frHndl)
  350. {
  351.     OSErr        err;
  352.     THPrint        prRecHndl;
  353.     short        oldRes;
  354.  
  355.     if (!(prRecHndl = (THPrint)NewHandle(sizeof(TPrint)))) return(memFullErr);
  356.  
  357.     oldRes = CurResFile();
  358.     PrOpen();
  359.  
  360.     if (!(err = PrError())) {
  361.  
  362.         BlockMove((Ptr)&(*frHndl)->d.doc.fhInfo.print, (Ptr)*prRecHndl, sizeof(TPrint));
  363.             /* Get data, valid or not. */
  364.  
  365.         if (!(*frHndl)->d.doc.fhInfo.printRecValid)
  366.             PrintDefault(prRecHndl);
  367.         else
  368.             PrValidate(prRecHndl);
  369.  
  370.         if (!(err = PrError())) {
  371.             UnhiliteWindows();
  372.             if (PrStlDialog(prRecHndl)) {
  373.                 BlockMove((Ptr)*prRecHndl, (Ptr)&(*frHndl)->d.doc.fhInfo.print, sizeof(TPrint));
  374.                 (*frHndl)->d.doc.fhInfo.printRecValid = true;
  375.             }
  376.             else err = userCanceledErr;
  377.             HiliteWindows();
  378.         }
  379.     }
  380.  
  381.     DisposeHandle((Handle)prRecHndl);
  382.     PrClose();
  383.     UseResFile(oldRes);
  384.  
  385.     return(err);
  386. }
  387.  
  388.  
  389.  
  390.